package com.wander.rep;

import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.androidplot.Plot.BorderStyle;
import com.androidplot.series.XYSeries;
import com.androidplot.ui.SizeLayoutType;
import com.androidplot.ui.SizeMetrics;
import com.androidplot.xy.BarFormatter;
import com.androidplot.xy.BarRenderer;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.SimpleXYSeries;
import com.androidplot.xy.XYPlot;
import com.androidplot.xy.XYStepMode;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.fima.cardsui.objects.CardStack;
import com.fima.cardsui.views.CardUI;
import com.wander.rep.cardui.MyCard;
import com.wander.rep.db4o.SingletonHelper;
import com.wander.rep.formats.DateFormat;
import com.wander.rep.formats.DomainFormat;
import com.wander.rep.patient.Feedback;
import com.wander.rep.patient.Issue;
import com.wander.rep.patient.Location;
import com.wander.rep.patient.Patient;

/**
 * A fragment representing a single Detail detail screen. This fragment is
 * either contained in a {@link DetailListActivity} in two-pane mode (on
 * tablets) or a {@link DetailActivity} on handsets.
 */
public class DetailFragment extends Fragment {
	/**
	 * The fragment argument representing the item ID that this fragment
	 * represents.
	 */
	public static final String ARG_ITEM_ID = "item_id";
	/**
	 * The fragment argument representing string ID
	 */
	public static final String STRING_RESULT_ID = "string_id";

	//private ImageView iv_activity, iv_movement, iv_temperature, iv_status;
	private ImageView iv_overlay_activity, iv_overlay_movement, iv_overlay_temperature, iv_overlay_status;
	private TextView patient_namesurname, tv_activity, tv_movement, tv_temperature, tv_status;
	private TextView score_activitylevel, score_temperature, score_patterns, score_status;

	/*
	 * Activity Level Plotting Objects
	 */
	private XYPlot activityLevelPlot;

	/*
	 * Temperature Level Plotting Objects
	 */
	private XYPlot temperatureLevelPlot;
	private XYPlot temperatureHistoryPlot;
	private SimpleXYSeries tempLevelsSeries = null;
	private SimpleXYSeries kitchenHistorySeries = null;
	private SimpleXYSeries bedroomHistorySeries = null;
	private SimpleXYSeries gardenHistorySeries = null;

	/*
	 * Visited Location Plot
	 */
	private XYPlot visitedLocPlot;
	private SimpleXYSeries visitedLocSeries = null;

	/*
	 * Card UI Object
	 */
	CardUI mCardView;

	private Typeface robotoBlack;

	int id;

	private Patient p;

	private Drawable GOOD; 
	private Drawable BAD;

	private ObjectContainer db;

	/**
	 * Mandatory empty constructor for the fragment manager to instantiate the
	 * fragment (e.g. upon screen orientation changes).
	 */
	public DetailFragment() {
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		if (getArguments().containsKey(ARG_ITEM_ID)) {
			// Load the dummy content specified by the fragment
			// arguments. In a real-world scenario, use a Loader
			// to load content from a content provider.
			id = Integer.parseInt(getArguments().getString(ARG_ITEM_ID));
		}

		updatePatient(null);

		robotoBlack = Typeface.createFromAsset(getActivity().getAssets(),
				"fonts/Roboto-Black.ttf");

		GOOD = getActivity().getResources().getDrawable(R.drawable.good);
		BAD  = getActivity().getResources().getDrawable(R.drawable.bad);
	}

	/*
	 * Update patient from DB and show latest profile data
	 */
	private void updatePatient(View rootView) {
		
		startDb4oSession();

		try
		{
			//((DetailListActivity) getActivity()).loadPatientfromDB();
			//p = ((DetailListActivity) getActivity()).getCurrentPatient();
			
			loadPatientfromDB();

			if(rootView != null)
			{
				rootView.invalidate();
				rootView.refreshDrawableState();
				rootView.postInvalidate();
			}
		}
		catch(Exception e)
		{
			Toast.makeText(getActivity(), "Cannot update from Patient DB. Error: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
		}
		//p = (new DetailListActivity).getCurentPatient();
		endDb4oSession();
	}

	/*
	 * Initialise database session through Singleton helper class
	 */
	private void startDb4oSession() {

		db = SingletonHelper.getInstance(this.getActivity().getApplicationContext()).getDatabaseSession();

	}
	
	/*
	 * Terminate database session
	 */
	private void endDb4oSession() {
		
		db.close();
		
	}

	/*
	 * Query database and return all saved Patient object instances
	 */
	protected boolean loadPatientfromDB() {

		ObjectSet<Patient> patients = db.query(Patient.class);

		if(!patients.isEmpty())
		{
			p = patients.get(0);
			return true;
		}
		else
		{
			return false;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		View rootView = new View(this.getActivity());
		rootView.invalidate();

		switch(id)
		{
		case 2:
			rootView = inflater.inflate(R.layout.fragment_activity_level, container, false);
			setActivityLevelPlot(rootView);
			break;
		case 3:
			rootView = inflater.inflate(R.layout.fragment_temperature_level, container, false);
			setTemperaturePlot(rootView);
			break;
		case 4:
			rootView = inflater.inflate(R.layout.fragment_visited_location, container, false);
			setVisitedLocationPlot(rootView);
			break;
		case 5:
			rootView = inflater.inflate(R.layout.activity_past_feedback, container, false);
			setCardLayout(rootView);
			break;
		default:
			updatePatient(rootView);
			rootView = inflater.inflate(R.layout.general_layout, container, false);
			setTextViewFonts(rootView);
			setPatientImageViewIndicators(rootView, inflater, container);
			break;
		}

		return rootView;
	}

	/*
	 * Sets the Dashboard Indicators with data relative to the Patient object loaded from Database
	 */
	private void setPatientImageViewIndicators(final View rootView, final LayoutInflater inflater, final ViewGroup container) {

		try
		{

			// Set the patient's name
			//patient_namesurname = (TextView) rootView.findViewById(R.id.patientNameSurname);
			//patient_namesurname.setText(p.getpName() + " " + p.getpSurname());
			//patient_namesurname.setTextColor(Color.GRAY);

			// Set the Activity Level imageviews
			iv_overlay_activity = (ImageView) rootView.findViewById(R.id.overlay_activity);
			iv_overlay_activity.setImageDrawable(GOOD);
			tv_activity.setTextColor(Color.GREEN);

			// Set Movement Pattern imageviews
			iv_overlay_movement = (ImageView) rootView.findViewById(R.id.overlay_movement_patterns);
			iv_overlay_movement.setImageDrawable(GOOD);
			tv_movement.setTextColor(Color.GREEN);

			// Set Temperature Level imageview
			iv_overlay_temperature = (ImageView) rootView.findViewById(R.id.overlay_temperature_level);
			iv_overlay_temperature.setImageDrawable(GOOD);
			tv_temperature.setTextColor(Color.GREEN);

			// Set Overall status
			iv_overlay_status = (ImageView) rootView.findViewById(R.id.overlay_status);

			score_activitylevel.setText(p.getpActivityLevel().getActivityLevel() + " ");
			score_patterns.setText(p.getpPattern().getName());
			score_temperature.setText(p.getpHome().getTempRoom1() + "\u2103");

			int issues = getUnsolvedIssues();
			if(issues == 0)
			{
				score_status.setText("OK");
				iv_overlay_status.setImageDrawable(GOOD);
				tv_status.setTextColor(Color.GREEN);
			}
			else
			{
				score_status.setText("Alert");
				iv_overlay_status.setImageDrawable(BAD);
				tv_status.setTextColor(Color.RED);
			}

		} catch (NullPointerException e)
		{
			Toast.makeText(getActivity(), "Cannot connect to Patient DB", Toast.LENGTH_LONG).show();
		}
	}

	/*
	 * Returns amount of unsolved Issues in Patient object
	 */
	private int getUnsolvedIssues() {
		ArrayList<Issue> issues = p.getpIssueHistory();
		int counter = 0;

		for(Issue issue : issues)
		{
			if(!issue.getIsSolved())
			{
				counter++;
			}
		}

		return counter;
	}

	/*
	 * Sets the font typeface for all TextViews in @param rootView
	 */
	private void setTextViewFonts(final View rootView) {

		patient_namesurname = (TextView) rootView.findViewById(R.id.patientNameSurname);
		patient_namesurname.setTypeface(robotoBlack);

		tv_activity = (TextView) rootView.findViewById(R.id.image_and_text_activity);
		tv_activity.setTypeface(robotoBlack);

		tv_movement = (TextView) rootView.findViewById(R.id.image_and_text_movement_patterns);
		tv_movement.setTypeface(robotoBlack);

		tv_temperature = (TextView) rootView.findViewById(R.id.image_and_text_temperature_level);
		tv_temperature.setTypeface(robotoBlack);

		tv_status = (TextView) rootView.findViewById(R.id.image_and_text_status);
		tv_status.setTypeface(robotoBlack);

		score_activitylevel = (TextView) rootView.findViewById(R.id.score_activitylevel);
		score_activitylevel.setTypeface(robotoBlack);

		score_patterns = (TextView) rootView.findViewById(R.id.score_movementpattern);
		score_patterns.setTypeface(robotoBlack);

		score_temperature = (TextView) rootView.findViewById(R.id.score_temperature);
		score_temperature.setTypeface(robotoBlack);

		score_status = (TextView) rootView.findViewById(R.id.score_status);
		score_status.setTypeface(robotoBlack);
	}

	/*
	 * Sets the necessary ActivityLevel Plots using hard coded series
	 */
	@SuppressWarnings("deprecation")
	private void setActivityLevelPlot(View view) {

		// initialize our XYPlot reference:
		activityLevelPlot = (XYPlot) view.findViewById(R.id.mySimpleXYPlot);
		activityLevelPlot.setTitle("Activity Level vs Time");

		// Create a couple arrays of y-values to plot:
		Number[] series1Numbers = { 0, 0, 0 , 0, 100, 400, 450, 500, 4500, 5400, 7000, 12600, 8500, 100, 200, 500, 8600, 12500, p.getpActivityLevel().getActivityLevel() }/*{0, 2, 3, 4, 5, 5, 7, 8, 9, 9, 9, 9, 10, 11, 12, 13, 14, 15, 15, 17, 18, 20, 23, 23, 24}*/;
		Number[] series2Numbers = {0, 20, 22, 23, 120, 350, 460, 507, 5800, 4900, 7000, 11900, 9600, 130, 140, 590, 8600, 13000, 1800, 900, 200, 21, 2, 9, 0};

		// Turn the above arrays into XYSeries':
		XYSeries series1 = new SimpleXYSeries(Arrays.asList(series1Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Current Activity Level");                             // Set the display title of the series

		// same as above
		XYSeries series2 = new SimpleXYSeries(Arrays.asList(series2Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Historical Activity Level");

		// Create a formatter to use for drawing a series using LineAndPointRenderer:
		LineAndPointFormatter series1Format = new LineAndPointFormatter(
				Color.rgb(0, 200, 0),                   // line color
				Color.rgb(0, 100, 0),                   // point color
				null);                                  // fill color (none)

		LineAndPointFormatter series2Format = new LineAndPointFormatter(
				Color.rgb(0, 0, 200),                   // line color
				Color.rgb(0, 0, 1000),                   // point color
				null);    

		// add a new series' to the xyplot:
		activityLevelPlot.addSeries(series1, series1Format);

		// same as above:
		activityLevelPlot.addSeries(series2, series2Format);

		// reduce the number of range labels
		activityLevelPlot.setTicksPerRangeLabel(3);

		// by default, AndroidPlot displays developer guides to aid in laying out your plot.
		// To get rid of them call disableAllMarkup():
		activityLevelPlot.disableAllMarkup();

		//Plot layout configurations
		activityLevelPlot.getGraphWidget().setTicksPerRangeLabel(100);
		activityLevelPlot.getGraphWidget().setTicksPerDomainLabel(1);
		activityLevelPlot.getGraphWidget().setRangeValueFormat(
				new DecimalFormat("#####.##"));
		activityLevelPlot.getGraphWidget().setDomainValueFormat(
				new DecimalFormat("#####.##"));
		activityLevelPlot.getGraphWidget().setRangeLabelWidth(25);
		activityLevelPlot.setRangeLabel("Activity");
		activityLevelPlot.setDomainLabel("Time of Day");
		activityLevelPlot.getLegendWidget().setSize(new SizeMetrics(12, SizeLayoutType.ABSOLUTE, 300, SizeLayoutType.ABSOLUTE));
		activityLevelPlot.disableAllMarkup();
		activityLevelPlot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 1);
		activityLevelPlot.setRangeStep(XYStepMode.INCREMENT_BY_VAL, 10);
		activityLevelPlot.setDomainBoundaries(0, 24, BoundaryMode.FIXED);
		activityLevelPlot.setDomainValueFormat(new DecimalFormat("#"));
		activityLevelPlot.getGraphWidget().setMarginLeft(25);
		activityLevelPlot.getGraphWidget().setMarginRight(5);
	}


	/*
	 * Sets the temperature plots with the latest User data
	 */
	@SuppressWarnings("deprecation")
	private void setTemperaturePlot(View view)
	{
		// Create a couple arrays of y-values to plot:
		Number[] tempLevel = {p.getpHome().getTempRoom1(), 26, 23};
		tempLevelsSeries = new SimpleXYSeries(Arrays.asList(tempLevel), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Current Temperature Level");

		temperatureLevelPlot = (XYPlot) view.findViewById(R.id.tempLevelsPlot);
		temperatureLevelPlot.setTitle("Current Temperature");
		temperatureLevelPlot.addSeries(tempLevelsSeries, new BarFormatter(Color.argb(100, 0, 200, 0), Color.rgb(0, 80, 0)));
		temperatureLevelPlot.setDomainStepValue(3);
		temperatureLevelPlot.setTicksPerRangeLabel(3);
		temperatureLevelPlot.setRangeBoundaries(0, 45, BoundaryMode.FIXED);
		temperatureLevelPlot.setDomainValueFormat(new DomainFormat());

		temperatureLevelPlot.setDomainLabel("Room");
		temperatureLevelPlot.getDomainLabelWidget().pack();
		temperatureLevelPlot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 1);
		temperatureLevelPlot.setRangeLabel("Temperature (Celsius)");
		temperatureLevelPlot.setRangeStep(XYStepMode.INCREMENT_BY_VAL, 1);
		temperatureLevelPlot.getRangeLabelWidget().pack();

		temperatureLevelPlot.setGridPadding(15, 0, 15, 0);
		temperatureLevelPlot.disableAllMarkup();

		BarRenderer br = (BarRenderer) temperatureLevelPlot.getRenderer(BarRenderer.class);
		if(br != null)
		{
			br.setBarWidth(55);
		}

		Number[] kitchenTempAvg = {22, 23, 24, 25, 24, 23, 24, 25, 26, 27, 27, 28, 28, 29, 28, 28, 27, 26, 25, 25, 24, 24, 23, 22, 22, 21};
		Number[] bedroomTempAvg = {28, 28, 29, 28, 29, 30, 30, 25, 26, 27, 27, 29, 29, 30, 31, 32, 31, 29, 28, 27, 26, 25, 24, 23, 23, 23};
		Number[] gardenTempAvg = {29, 32, 33, 32, 32, 33, 34, 35, 36, 37, 37, 36, 36, 35, 34, 33, 32, 32, 32, 31, 29, 28, 27, 26, 26, 25};

		kitchenHistorySeries = new SimpleXYSeries(Arrays.asList(kitchenTempAvg), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Kitchen");
		bedroomHistorySeries = new SimpleXYSeries(Arrays.asList(bedroomTempAvg), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Bedroom");
		gardenHistorySeries = new SimpleXYSeries(Arrays.asList(gardenTempAvg), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Garden");

		temperatureHistoryPlot = (XYPlot) view.findViewById(R.id.tempHistoryPlot);
		temperatureHistoryPlot.setTitle("Historical Temperature");
		temperatureHistoryPlot.setRangeBoundaries(0, 45, BoundaryMode.FIXED);
		temperatureHistoryPlot.setDomainBoundaries(0, 30, BoundaryMode.FIXED);
		temperatureHistoryPlot.addSeries(kitchenHistorySeries, new LineAndPointFormatter(Color.rgb(100, 100, 200), Color.BLACK, null));
		temperatureHistoryPlot.addSeries(bedroomHistorySeries, new LineAndPointFormatter(Color.rgb(100, 200, 100), Color.BLACK, null));
		temperatureHistoryPlot.addSeries(gardenHistorySeries, new LineAndPointFormatter(Color.rgb(200, 100, 100), Color.BLACK, null));
		temperatureHistoryPlot.setDomainStepValue(5);
		temperatureHistoryPlot.setTicksPerRangeLabel(3);
		temperatureHistoryPlot.setDomainLabel("Time of Day");
		temperatureHistoryPlot.getDomainLabelWidget().pack();
		temperatureHistoryPlot.setRangeLabel("Temperature (Celsius)");
		temperatureHistoryPlot.getRangeLabelWidget().pack();
		temperatureHistoryPlot.disableAllMarkup();

		temperatureHistoryPlot.setRangeStep(XYStepMode.INCREMENT_BY_VAL, 1);
		temperatureHistoryPlot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 2);
		temperatureHistoryPlot.setDomainBoundaries(0, 24, BoundaryMode.FIXED);
		temperatureHistoryPlot.setDomainValueFormat(new DecimalFormat("##.##"));
	}

	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onDestroyView()
	 */
	@Override
	public void onDestroyView() {

		if(activityLevelPlot != null)
		{
			((ViewManager)activityLevelPlot.getParent()).removeView(activityLevelPlot);
		}
		super.onDestroyView();
	}

	/*
	 * Sets the visited location plots with the latest user data
	 */
	@SuppressWarnings({ "deprecation" })
	private void setVisitedLocationPlot(View view) {

		ArrayList<Location> list = p.getpPatternHistory();
		Number[] time = new Number[6];
		Number[] episodeNumber = new Number[6];
		final String[] episode = new String[6];

		int x = 0;

		for(int m = 0; m < 6; m++)
		{
			time[x] = list.get(m).getTimestamp();
			episode[x] = list.get(m).getName();
			episodeNumber[x] = x;
			x++;
		}

		Date date = new Date(p.getpPattern().getTimestamp()*1000);
		SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");

		Toast.makeText(getActivity(), "User's last trip was between " + p.getpPattern().getName() + " at " + dateFormat.format(date), Toast.LENGTH_LONG).show();

		visitedLocSeries = new SimpleXYSeries(Arrays.asList(time), Arrays.asList(episodeNumber), "Time");

		visitedLocPlot = (XYPlot) view.findViewById(R.id.visitedLocPlot);
		visitedLocPlot.setTitle("Visited Locations");
		visitedLocPlot.addSeries(visitedLocSeries, new LineAndPointFormatter(Color.rgb(100, 100, 200), Color.BLACK, null));
		visitedLocPlot.setDomainValueFormat(new DateFormat());
		visitedLocPlot.setRangeValueFormat(new NumberFormat()
		{

			private static final long serialVersionUID = 1L;

			@Override
			public StringBuffer format(double obj, StringBuffer arg1,
					FieldPosition arg2) {
				Number num = (Number) obj;

				arg1.append(episode[num.intValue()]);

				return arg1;
			}

			@Override
			public StringBuffer format(long value, StringBuffer buffer,
					FieldPosition field) {
				// TODO Auto-generated method stub
				return null;
			}

			@Override
			public Number parse(String string, ParsePosition position) {
				// TODO Auto-generated method stub
				return null;
			}

		});
		visitedLocPlot.setRangeStep(XYStepMode.INCREMENT_BY_VAL, 1);
		visitedLocPlot.getGraphWidget().setMarginTop(25);
		visitedLocPlot.getGraphWidget().setMarginBottom(10);
		visitedLocPlot.getGraphWidget().setMarginLeft(100);
		visitedLocPlot.setBorderStyle(BorderStyle.SQUARE, null, null);
		visitedLocPlot.disableAllMarkup();
	}

	/*
	 * Sets the card layout with issues for caregivers to reply
	 */
	private void setCardLayout(View rootView) 
	{
		try
		{
			ArrayList<Issue> issues = p.getpIssueHistory();

			mCardView = (CardUI) rootView.findViewById(R.id.cardsview);
			mCardView.setSwipeable(false);

			for(final Issue issue : issues)
			{
				// create a stack
				CardStack stack = new CardStack();

				Date ts = issue.getDate();
				stack.setTitle(new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(ts));

				// issue's status indicator
				int indicator;
				if(issue.getIsSolved())
				{
					indicator = R.drawable.good;
				}
				else
				{
					indicator = R.drawable.bad;
				}

				// feedback list associated with issue id
				ArrayList<Feedback> fb = issue.getFeedbackList();

				// get indicator as drawable value
				Drawable d = getResources().getDrawable(indicator);

				for(Feedback feedback : fb)
				{
					MyCard fCard = new MyCard(feedback.getUsername() + " commented...", feedback.getComment());
					stack.add(fCard);
				}

				MyCard mCard = new MyCard(issue.getTitleString(), issue.getErrorString(), d);

				mCard.setOnClickListener(new OnClickListener()
				{
					/*
					 * (non-Javadoc)
					 * @see android.view.View.OnClickListener#onClick(android.view.View)
					 */
					@Override
					public void onClick(View arg0) {

						SubmitFeedbackDialog sfd = new SubmitFeedbackDialog();

						Bundle mBundle = new Bundle();
						mBundle.putSerializable("issue", issue);

						sfd.setArguments(mBundle);
						sfd.show(getFragmentManager(), getTag());
					}

				});

				stack.add(mCard);

				// add stack to cardView
				mCardView.addStack(stack);
			}

			// draw cards
			mCardView.refresh();		
		}
		catch(Exception e)
		{
			Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
		}
	}
}
